#include "pch.hpp"
#include "PageRegion.hpp"
#include "SystemException.hpp"

static size_t getPageSize()
{
	SYSTEM_INFO si = { 0 };
	::GetSystemInfo(&si);
	return si.dwPageSize;
}

static size_t getPageCount(size_t byteCount)
{
	return (byteCount + Pdf::PageRegion::pageSize - 1) / Pdf::PageRegion::pageSize;
}

static size_t getPageAlignedByteCount(size_t byteCount)
{
	return (byteCount + Pdf::PageRegion::pageSize - 1) & ~(Pdf::PageRegion::pageSize - 1);
}

namespace Pdf
{
	size_t const PageRegion::pageSize = getPageSize();

	PageRegion::PageRegion(size_t byteCount)
		: base(0)
		, pageCount(::getPageCount(byteCount))
	{
		PVOID pointer = ::VirtualAlloc(NULL, pageCount * pageSize, MEM_RESERVE, PAGE_NOACCESS);
		if (NULL == pointer)
			throw SystemException();
		base = static_cast<char *>(pointer);
	}

	PageRegion::~PageRegion()
	{
		::VirtualFree(base, 0, MEM_RELEASE);
	}

	size_t PageRegion::getPageCount() const
	{
		return pageCount;
	}

	char * PageRegion::getPage(size_t pageIndex) const
	{
		return base + pageSize * pageIndex;
	}

	size_t PageRegion::getPageIndex(char * page) const
	{
		return (page - base) / pageSize;
	}

	char * PageRegion::acquirePage(size_t pageIndex)
	{
		PVOID page = ::VirtualAlloc(getPage(pageIndex), pageSize, MEM_COMMIT, PAGE_READWRITE);
		if (NULL == page)
			throw SystemException();
		return static_cast<char*>(page);
	}

	void PageRegion::releasePage(size_t pageIndex)
	{
		::VirtualFree(getPage(pageIndex), pageSize, MEM_DECOMMIT);
	}
}
